<?php

namespace ORM;

use Database\Connection;
use Database\QueryBuilder;

class RelationManager {
    protected $connection;
    
    /**
     * 构造函数
     */
    public function __construct(Connection $connection) {
        $this->connection = $connection;
    }
    
    /**
     * 处理一对一关系
     * 
     * @param Model $model 源模型实例
     * @param string $related 关联模型类名
     * @param string $foreignKey 外键
     * @param string $localKey 本地键
     * @return Model|null
     */
    public function hasOne(Model $model, $related, $foreignKey = null, $localKey = null) {
        // 实例化关联模型
        $relatedModel = new $related();
        
        // 确定外键和本地键
        $foreignKey = $foreignKey ?: $model->getTable() . '_id';
        $localKey = $localKey ?: $model->getPrimaryKey();
        
        // 获取本地键的值
        $localKeyValue = $model->getAttribute($localKey);
        
        if ($localKeyValue === null) {
            return null;
        }
        
        // 创建查询构建器
        $query = new QueryBuilder($this->connection);
        $query->table($relatedModel->getTable());
        
        // 查询关联记录
        return $query->where($foreignKey, $localKeyValue)->first();
    }
    
    /**
     * 处理一对多关系
     * 
     * @param Model $model 源模型实例
     * @param string $related 关联模型类名
     * @param string $foreignKey 外键
     * @param string $localKey 本地键
     * @return array
     */
    public function hasMany(Model $model, $related, $foreignKey = null, $localKey = null) {
        // 实例化关联模型
        $relatedModel = new $related();
        
        // 确定外键和本地键
        $foreignKey = $foreignKey ?: $model->getTable() . '_id';
        $localKey = $localKey ?: $model->getPrimaryKey();
        
        // 获取本地键的值
        $localKeyValue = $model->getAttribute($localKey);
        
        if ($localKeyValue === null) {
            return [];
        }
        
        // 创建查询构建器
        $query = new QueryBuilder($this->connection);
        $query->table($relatedModel->getTable());
        
        // 查询关联记录
        return $query->where($foreignKey, $localKeyValue)->get();
    }
    
    /**
     * 处理多对一关系（反向一对多）
     * 
     * @param Model $model 源模型实例
     * @param string $related 关联模型类名
     * @param string $foreignKey 外键
     * @param string $ownerKey 关联模型主键
     * @return Model|null
     */
    public function belongsTo(Model $model, $related, $foreignKey = null, $ownerKey = null) {
        // 实例化关联模型
        $relatedModel = new $related();
        
        // 确定外键和关联模型主键
        $foreignKey = $foreignKey ?: $relatedModel->getTable() . '_id';
        $ownerKey = $ownerKey ?: $relatedModel->getPrimaryKey();
        
        // 获取外键的值
        $foreignKeyValue = $model->getAttribute($foreignKey);
        
        if ($foreignKeyValue === null) {
            return null;
        }
        
        // 创建查询构建器
        $query = new QueryBuilder($this->connection);
        $query->table($relatedModel->getTable());
        
        // 查询关联记录
        return $query->where($ownerKey, $foreignKeyValue)->first();
    }
    
    /**
     * 处理多对多关系
     * 
     * @param Model $model 源模型实例
     * @param string $related 关联模型类名
     * @param string $table 中间表名
     * @param string $foreignPivotKey 当前模型在中间表的外键
     * @param string $relatedPivotKey 关联模型在中间表的外键
     * @param string $parentKey 当前模型主键
     * @param string $relatedKey 关联模型主键
     * @return array
     */
    public function belongsToMany(Model $model, $related, $table = null, $foreignPivotKey = null, $relatedPivotKey = null, $parentKey = null, $relatedKey = null) {
        // 实例化关联模型
        $relatedModel = new $related();
        
        // 确定中间表名
        if ($table === null) {
            $tables = [
                $model->getTable(),
                $relatedModel->getTable()
            ];
            sort($tables);
            $table = implode('_', $tables);
        }
        
        // 确定外键
        $foreignPivotKey = $foreignPivotKey ?: $model->getTable() . '_id';
        $relatedPivotKey = $relatedPivotKey ?: $relatedModel->getTable() . '_id';
        
        // 确定主键
        $parentKey = $parentKey ?: $model->getPrimaryKey();
        $relatedKey = $relatedKey ?: $relatedModel->getPrimaryKey();
        
        // 获取当前模型主键的值
        $parentKeyValue = $model->getAttribute($parentKey);
        
        if ($parentKeyValue === null) {
            return [];
        }
        
        // 创建查询构建器
        $query = new QueryBuilder($this->connection);
        
        // 查询关联记录
        $records = $query->table($relatedModel->getTable())
            ->select([
                $relatedModel->getTable() . '.*'
            ])
            ->join($table, function($join) use ($table, $relatedPivotKey, $relatedModel, $relatedKey) {
                $join->on($table . '.' . $relatedPivotKey, '=', $relatedModel->getTable() . '.' . $relatedKey);
            })
            ->where($table . '.' . $foreignPivotKey, $parentKeyValue)
            ->get();
        
        return $records;
    }
    
    /**
     * 预加载关联
     * 
     * @param array $models 模型集合
     * @param string $relation 关联名称
     * @param callable $callback 回调函数
     * @return array
     */
    public function eagerLoad(array $models, $relation, $callback = null) {
        if (empty($models)) {
            return $models;
        }
        
        // 获取第一个模型实例来调用关联方法
        $model = reset($models);
        
        // 调用关联方法获取关联配置
        $relationConfig = $model->$relation();
        
        // 根据关联类型执行不同的预加载逻辑
        switch ($relationConfig['type']) {
            case 'hasOne':
            case 'belongsTo':
                return $this->eagerLoadOneToOne($models, $relationConfig, $relation, $callback);
            case 'hasMany':
                return $this->eagerLoadOneToMany($models, $relationConfig, $relation, $callback);
            case 'belongsToMany':
                return $this->eagerLoadManyToMany($models, $relationConfig, $relation, $callback);
            default:
                throw new \Exception("不支持的关联类型: {$relationConfig['type']}");
        }
    }
    
    /**
     * 预加载一对一关联
     */
    protected function eagerLoadOneToOne(array $models, array $relationConfig, $relation, $callback = null) {
        // 提取关联配置
        $related = $relationConfig['related'];
        $foreignKey = $relationConfig['foreignKey'];
        $localKey = $relationConfig['localKey'];
        
        // 实例化关联模型
        $relatedModel = new $related();
        
        // 收集所有模型的本地键值
        $keys = [];
        foreach ($models as $model) {
            $keyValue = $model->getAttribute($localKey);
            if ($keyValue !== null) {
                $keys[] = $keyValue;
            }
        }
        
        if (empty($keys)) {
            return $models;
        }
        
        // 创建查询构建器
        $query = new QueryBuilder($this->connection);
        $query->table($relatedModel->getTable());
        
        // 应用自定义查询条件
        if ($callback) {
            $callback($query);
        }
        
        // 查询所有关联记录
        $results = $query->whereIn($foreignKey, $keys)->get();
        
        // 将关联记录映射到模型
        $dictionary = [];
        foreach ($results as $result) {
            $dictionary[$result[$foreignKey]] = $result;
        }
        
        // 将关联记录附加到模型
        foreach ($models as $model) {
            $keyValue = $model->getAttribute($localKey);
            if (isset($dictionary[$keyValue])) {
                $model->setRelation($relation, $dictionary[$keyValue]);
            } else {
                $model->setRelation($relation, null);
            }
        }
        
        return $models;
    }
    
    /**
     * 预加载一对多关联
     */
    protected function eagerLoadOneToMany(array $models, array $relationConfig, $relation, $callback = null) {
        // 提取关联配置
        $related = $relationConfig['related'];
        $foreignKey = $relationConfig['foreignKey'];
        $localKey = $relationConfig['localKey'];
        
        // 实例化关联模型
        $relatedModel = new $related();
        
        // 收集所有模型的本地键值
        $keys = [];
        foreach ($models as $model) {
            $keyValue = $model->getAttribute($localKey);
            if ($keyValue !== null) {
                $keys[] = $keyValue;
            }
        }
        
        if (empty($keys)) {
            return $models;
        }
        
        // 创建查询构建器
        $query = new QueryBuilder($this->connection);
        $query->table($relatedModel->getTable());
        
        // 应用自定义查询条件
        if ($callback) {
            $callback($query);
        }
        
        // 查询所有关联记录
        $results = $query->whereIn($foreignKey, $keys)->get();
        
        // 将关联记录分组
        $dictionary = [];
        foreach ($results as $result) {
            $dictionary[$result[$foreignKey]][] = $result;
        }
        
        // 将关联记录附加到模型
        foreach ($models as $model) {
            $keyValue = $model->getAttribute($localKey);
            if (isset($dictionary[$keyValue])) {
                $model->setRelation($relation, $dictionary[$keyValue]);
            } else {
                $model->setRelation($relation, []);
            }
        }
        
        return $models;
    }
    
    /**
     * 预加载多对多关联
     */
    protected function eagerLoadManyToMany(array $models, array $relationConfig, $relation, $callback = null) {
        // 提取关联配置
        $related = $relationConfig['related'];
        $table = $relationConfig['table'];
        $foreignPivotKey = $relationConfig['foreignPivotKey'];
        $relatedPivotKey = $relationConfig['relatedPivotKey'];
        $parentKey = $relationConfig['parentKey'];
        $relatedKey = $relationConfig['relatedKey'];
        
        // 实例化关联模型
        $relatedModel = new $related();
        
        // 收集所有模型的主键值
        $keys = [];
        foreach ($models as $model) {
            $keyValue = $model->getAttribute($parentKey);
            if ($keyValue !== null) {
                $keys[] = $keyValue;
            }
        }
        
        if (empty($keys)) {
            return $models;
        }
        
        // 创建查询构建器
        $query = new QueryBuilder($this->connection);
        
        // 应用自定义查询条件
        if ($callback) {
            $callback($query);
        }
        
        // 查询所有关联记录
        $results = $query->table($relatedModel->getTable())
            ->select([
                $relatedModel->getTable() . '.*',
                $table . '.' . $foreignPivotKey . ' as pivot_' . $foreignPivotKey
            ])
            ->join($table, function($join) use ($table, $relatedPivotKey, $relatedModel, $relatedKey) {
                $join->on($table . '.' . $relatedPivotKey, '=', $relatedModel->getTable() . '.' . $relatedKey);
            })
            ->whereIn($table . '.' . $foreignPivotKey, $keys)
            ->get();
        
        // 将关联记录分组
        $dictionary = [];
        foreach ($results as $result) {
            $pivotKey = 'pivot_' . $foreignPivotKey;
            $dictionary[$result[$pivotKey]][] = $result;
        }
        
        // 将关联记录附加到模型
        foreach ($models as $model) {
            $keyValue = $model->getAttribute($parentKey);
            if (isset($dictionary[$keyValue])) {
                $model->setRelation($relation, $dictionary[$keyValue]);
            } else {
                $model->setRelation($relation, []);
            }
        }
        
        return $models;
    }
}